package utils

import (
	"crypto/aes"
	"crypto/cipher"
	"crypto/rand"
	"crypto/sha256"
	"encoding/base64"
	"errors"
	"io"
	"regexp"
	"strings"
)

// SensitiveUtils 敏感信息处理工具
type SensitiveUtils struct {
	encryptionKey []byte
}

// NewSensitiveUtils 创建新的敏感信息处理工具实例
// encryptionKey 是用于加密解密的密钥，长度必须为16, 24或32字节(AES-128, AES-192或AES-256)
func New(encryptionKey string) *SensitiveUtils {
	// 使用SHA-256哈希确保密钥长度正确
	//switch len(encryptionKey) {
	//case 16, 24, 32:
	//	return &SensitiveUtils{encryptionKey: []byte(encryptionKey)}, nil
	//default:
	//	return nil, fmt.Errorf("invalid key length %d, must be 16, 24 or 32 bytes", len(encryptionKey))
	//}
	hash := sha256.Sum256([]byte(encryptionKey))
	return &SensitiveUtils{encryptionKey: hash[:]}
}

// DesensitizePhone 手机号脱敏
// 保留前3位和后4位，中间用****代替
// 例如：138****1234
func (s *SensitiveUtils) DesensitizePhone(phone string) string {
	if len(phone) < 7 {
		return strings.Repeat("*", len(phone))
	}
	return phone[:3] + "****" + phone[len(phone)-4:]
}

// DesensitizeEmail 邮箱脱敏
// 保留邮箱前缀的前1位和后1位，中间用***代替，域名完整显示
// 例如：a***b@example.com
func (s *SensitiveUtils) DesensitizeEmail(email string) (string, error) {
	parts := strings.Split(email, "@")
	if len(parts) != 2 {
		return "", errors.New("invalid email format")
	}

	prefix := parts[0]
	domain := parts[1]

	if len(prefix) <= 2 {
		return strings.Repeat("*", len(prefix)) + "@" + domain, nil
	}

	desensitizedPrefix := string(prefix[0]) + "***" + string(prefix[len(prefix)-1])
	return desensitizedPrefix + "@" + domain, nil
}

// DesensitizeIDCard 身份证号脱敏
// 保留前1位和后1位，中间用****代替
func (s *SensitiveUtils) DesensitizeIDCard(idCard string) string {
	if len(idCard) <= 2 {
		return strings.Repeat("*", len(idCard))
	}
	return string(idCard[0]) + strings.Repeat("*", len(idCard)-2) + string(idCard[len(idCard)-1])
}

// DesensitizeBankCard 银行卡号脱敏
// 保留前4位和后4位，中间用****代替
func (s *SensitiveUtils) DesensitizeBankCard(bankCard string) string {
	if len(bankCard) < 8 {
		return strings.Repeat("*", len(bankCard))
	}
	return bankCard[:4] + "****" + bankCard[len(bankCard)-4:]
}

// Encrypt 加密敏感数据
func (s *SensitiveUtils) Encrypt(plaintext string) (string, error) {
	block, err := aes.NewCipher(s.encryptionKey)
	if err != nil {
		return "", err
	}

	// 使用GCM模式
	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	nonce := make([]byte, gcm.NonceSize())
	if _, err = io.ReadFull(rand.Reader, nonce); err != nil {
		return "", err
	}

	ciphertext := gcm.Seal(nonce, nonce, []byte(plaintext), nil)
	return base64.StdEncoding.EncodeToString(ciphertext), nil
}

// Decrypt 解密敏感数据
func (s *SensitiveUtils) Decrypt(encodedCiphertext string) (string, error) {
	ciphertext, err := base64.StdEncoding.DecodeString(encodedCiphertext)
	if err != nil {
		return "", err
	}

	block, err := aes.NewCipher(s.encryptionKey)
	if err != nil {
		return "", err
	}

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", err
	}

	nonceSize := gcm.NonceSize()
	if len(ciphertext) < nonceSize {
		return "", errors.New("ciphertext too short")
	}

	nonce, ciphertext := ciphertext[:nonceSize], ciphertext[nonceSize:]
	plaintext, err := gcm.Open(nil, nonce, ciphertext, nil)
	if err != nil {
		return "", err
	}

	return string(plaintext), nil
}

// IsValidPhone 验证手机号格式
func (s *SensitiveUtils) IsValidPhone(phone string) bool {
	// 简单的手机号验证正则，可根据实际需求调整
	pattern := `^1[3-9]\d{9}$`
	matched, err := regexp.MatchString(pattern, phone)
	return err == nil && matched
}

// IsValidEmail 验证邮箱格式
func (s *SensitiveUtils) IsValidEmail(email string) bool {
	// 简单的邮箱验证正则
	pattern := `^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`
	matched, err := regexp.MatchString(pattern, email)
	return err == nil && matched
}

// GenerateRandomPassword 生成随机密码
// length: 密码长度
// useSpecialChars: 是否使用特殊字符
func (s *SensitiveUtils) GenerateRandomPassword(length int, useSpecialChars bool) (string, error) {
	var chars string
	if useSpecialChars {
		chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*()_+"
	} else {
		chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
	}

	bytes := make([]byte, length)
	if _, err := rand.Read(bytes); err != nil {
		return "", err
	}

	for i, b := range bytes {
		bytes[i] = chars[b%byte(len(chars))]
	}

	return string(bytes), nil
}
